package com.qsw.selectview.view;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import com.qsw.selectview.R;

import java.util.LinkedList;
import java.util.List;

/**
 * 内容选择控件
 */
public class SelectView extends ViewGroup {
    private static final String TAG = "TAG_SelectView";
    /**
     * 要显示的选项数据
     */
    private List<String> mDataList;

    /**
     * 可换行的布局
     */
    private RadioGroup mAutoNewLineRadioGroup;
    /**
     * 当条目选中状态改变时的回调
     */
    private OnItemCheckedChangeListener mOnItemCheckedChangeListener;

    /**
     * true：多选；fasle：单选
     */
    private boolean mMultiSelect = false;
    /**
     * 选中内容的区别
     */
    private SelectShowMode mSelectShowMode = SelectShowMode.TEXTCOLOR;

    /**
     * 内容文字字号，单位：px
     */
    private int mItemTextSize = SVUtil.sp2px(getContext(), 15);
    /**
     * 选中时的文字颜色
     */
    private int mCheckedTextColor = getResources().getColor(R.color.sv_color_text_select);
    /**
     * 未选中时的文字颜色
     */
    private int mNormalTextColor = getResources().getColor(R.color.sv_color_text_noselect);

    /**
     * 选中时的背景填充颜色
     */
    private int mCheckedBackgroundSolidColor = getResources().getColor(R.color.sv_color_bg_select);
    /**
     * 未选中时的背景填充颜色
     */
    private int mNormalBackgroundSolidColor = getResources().getColor(R.color.sv_color_bg_noselect);
    /**
     * 选中时的背景边框颜色
     */
    private int mCheckedBackgroundStrokeColor = getResources().getColor(R.color.sv_color_stroke_select);
    /**
     * 未选中时的背景边框颜色
     */
    private int mNormalBackgroundStrokeColor = getResources().getColor(R.color.sv_color_stroke_noselect);
    /**
     * 背景边框宽度，单位：px
     */
    private int mBackgroundStrokeWidth = SVUtil.dp2px(getContext(), 1);
    /**
     * 选中时的背景
     */
    private Drawable mCheckedBackground;
    /**
     * 未选中时的背景
     */
    private Drawable mNormalBackground;

    /**
     * 内容左内边距，单位：px
     */
    private int mItemPaddingLeft = SVUtil.dp2px(getContext(), 5);
    /**
     * 内容上内边距，单位：px
     */
    private int mItemPaddingTop = SVUtil.dp2px(getContext(), 5);
    /**
     * 内容右内边距，单位：px
     */
    private int mItemPaddingRight = SVUtil.dp2px(getContext(), 5);
    /**
     * 内容下内边距，单位：px
     */
    private int mItemPaddingBottom = SVUtil.dp2px(getContext(), 5);
    /**
     * 内容左右外边距，单位：px
     */
    private int mItemMarginLR = SVUtil.dp2px(getContext(), 5);
    /**
     * 内容上下外边距，单位：px
     */
    private int mItemMarginTB = SVUtil.dp2px(getContext(), 5);

    public SelectView(Context context) {
        this(context, null);
    }

    public SelectView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SelectView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
//        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        measureChild(mAutoNewLineRadioGroup,
                MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY),
                heightMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY) {
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mAutoNewLineRadioGroup.getMeasuredWidth(), widthMode);
        }
        if (heightMode != MeasureSpec.EXACTLY) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(mAutoNewLineRadioGroup.getMeasuredHeight(), heightMode);
        }

        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mAutoNewLineRadioGroup.layout(0, 0, r - l, b - t);
    }

    /**
     * 初始化基本内容
     */
    private void init() {
        mAutoNewLineRadioGroup = new AutoNewLineRadioGroup(getContext());
        mAutoNewLineRadioGroup.setOnCheckedChangeListener(mOnSingleCheckedChangeListener);

        LayoutParams layoutParams = new RadioGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        addView(mAutoNewLineRadioGroup, layoutParams);

        refreshView();
    }

    /**
     * 刷新显示
     */
    private void refreshView() {
        mAutoNewLineRadioGroup.removeAllViews();

        if (mDataList != null && mDataList.size() > 0) {
            for (String str : mDataList) {
                CompoundButton compoundButton;
                if (mMultiSelect) {
                    compoundButton = new CheckBox(getContext(), null, 0, R.style.SV_ButtonChooseStyle);
                    compoundButton.setOnCheckedChangeListener(mOnMultiCheckedChangeListener);
                } else {
                    compoundButton = new RadioButton(getContext(), null, 0, R.style.SV_ButtonChooseStyle);
                }
                compoundButton.setText(str);
                if ((mSelectShowMode == SelectShowMode.TEXTCOLOR_TEXTBORDER) || (mSelectShowMode == SelectShowMode.TEXTCOLOR)) {
                    compoundButton.setTextColor(SVUtil.getColorSelector(mCheckedTextColor, mNormalTextColor));
                }
                if ((mSelectShowMode == SelectShowMode.TEXTCOLOR_TEXTBORDER) || (mSelectShowMode == SelectShowMode.TEXTBORDER)) {
                    Drawable checkedBackground;
                    Drawable normalBackground;
                    if (mCheckedBackground == null) {
                        checkedBackground = SVUtil.getShapeDrawable(mCheckedBackgroundSolidColor,
                                mCheckedBackgroundStrokeColor,
                                mBackgroundStrokeWidth,
                                0, 0, SVUtil.dp2px(getContext(), 3));
                    } else {
                        checkedBackground = mCheckedBackground;
                    }
                    if (mNormalBackground == null) {
                        normalBackground = SVUtil.getShapeDrawable(mNormalBackgroundSolidColor,
                                mNormalBackgroundStrokeColor,
                                mBackgroundStrokeWidth,
                                0, 0, SVUtil.dp2px(getContext(), 3));
                    } else {
                        normalBackground = mNormalBackground;
                    }
                    compoundButton.setBackground(SVUtil.getDrawableSelector(checkedBackground, normalBackground));
                }
                compoundButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mItemTextSize);
                compoundButton.setPadding(mItemPaddingLeft, mItemPaddingTop, mItemPaddingRight, mItemPaddingBottom);
                mAutoNewLineRadioGroup.addView(compoundButton);
                RadioGroup.LayoutParams layoutParams = (RadioGroup.LayoutParams) compoundButton.getLayoutParams();
                layoutParams.setMargins(mItemMarginLR, mItemMarginTB, mItemMarginLR, mItemMarginTB);
                compoundButton.setLayoutParams(layoutParams);
            }
        }
    }

    /**
     * 设置显示数据，之前的数据将被全部丢弃
     *
     * @param dataList 要显示的数据
     */
    public void setData(List<String> dataList) {
        mDataList = dataList;

        refreshView();
    }

    /**
     * 增加显示数据到尾部
     *
     * @param dataStr 要增加的数据
     */
    public void addData(String dataStr) {
        if (mDataList == null) {
            mDataList = new LinkedList<>();
        }
        mDataList.add(dataStr);

        refreshView();
    }

    /**
     * 增加显示数据到指定位置
     *
     * @param index   要增加位置的索引
     * @param dataStr 要增加的数据
     */
    public void addData(int index, String dataStr) {
        if (mDataList == null) {
            mDataList = new LinkedList<>();
        }
        mDataList.add(index, dataStr);

        refreshView();
    }

    /**
     * 增加显示数据到尾部
     *
     * @param dataList 要增加的数据列表
     */
    public void addData(List<String> dataList) {
        if (dataList == null) {
            return;
        }
        if (mDataList == null) {
            mDataList = new LinkedList<>();
        }
        mDataList.addAll(dataList);

        refreshView();
    }

    /**
     * 清空显示的数据
     */
    public void cleanData() {
        if (mDataList == null) {
            return;
        }
        mDataList.clear();

        refreshView();
    }

    /**
     * 移出一个数据
     *
     * @param dataStr 待移出的数据
     * @return true：存在且移出；false：不存在
     */
    public boolean removeData(String dataStr) {
        if (mDataList == null || !mDataList.contains(dataStr)) {
            return false;
        }
        return mDataList.remove(dataStr);
    }

    /**
     * 移出数据集合中的所有数据
     *
     * @param dataList 待移出的数据集合
     * @return true：存在且移出；false：不存在
     */
    public void removeData(List<String> dataList) {
        if (mDataList == null || mDataList.isEmpty() || dataList == null || dataList.isEmpty()) {
            return;
        }
        mDataList.removeAll(dataList);
    }

    /**
     * 是否为多选模式
     *
     * @return true：多选；fasle：单选
     */
    public boolean isMultiSelect() {
        return mMultiSelect;
    }

    /**
     * 设置是否为多选模式，true：多选；fasle：单选
     *
     * @param multiSelect true：多选；fasle：单选
     */
    public void setMultiSelect(boolean multiSelect) {
        this.mMultiSelect = multiSelect;

        refreshView();
    }

    /**
     * 设置内容文字字号
     *
     * @param textSizePX 内容文字字号，单位：px
     */
    public void setItemTextSize(int textSizePX) {
        mItemTextSize = textSizePX;

        refreshView();
    }

    /**
     * 获取内容文字字号
     *
     * @return 内容文字字号，单位：px
     */
    public int getItemTextSize() {
        return mItemTextSize;
    }

    /**
     * 设置内容内边距
     *
     * @param left   内容左内边距，单位：px
     * @param top    内容上内边距，单位：px
     * @param right  内容右内边距，单位：px
     * @param bottom 内容下内边距，单位：px
     */
    public void setItemPadding(int left, int top, int right, int bottom) {
        mItemPaddingLeft = left;
        mItemPaddingTop = top;
        mItemPaddingRight = right;
        mItemPaddingBottom = bottom;

        refreshView();
    }

    /**
     * 获取内容左内边距
     *
     * @return 内容左内边距，单位：px
     */
    public int getItemPaddingLeft() {
        return mItemPaddingLeft;
    }

    /**
     * 获取内容上内边距
     *
     * @return 内容左内边距，单位：px
     */
    public int getItemPaddingTop() {
        return mItemPaddingTop;
    }

    /**
     * 获取内容右内边距
     *
     * @return 内容左内边距，单位：px
     */
    public int getItemPaddingRight() {
        return mItemPaddingRight;
    }

    /**
     * 获取内容下内边距
     *
     * @return 内容左内边距，单位：px
     */
    public int getItemPaddingBottom() {
        return mItemPaddingBottom;
    }

    /**
     * 设置内容外边距
     *
     * @param lr 内容左右外边距，单位：px
     * @param tb 内容上下外边距，单位：px
     */
    public void setItemMargin(int lr, int tb) {
        mItemMarginLR = lr;
        mItemMarginTB = tb;

        refreshView();
    }

    /**
     * 获取内容左右外边距
     *
     * @return 内容左右外边距
     */
    public int getItemMarginLR() {
        return mItemMarginLR;
    }

    /**
     * 获取内容上下外边距
     *
     * @return 内容上下外边距
     */
    public int getItemMarginTB() {
        return mItemMarginTB;
    }

    /**
     * 设置选中内容的区别
     *
     * @param selectShowMode 选中内容的区别
     */
    public void setSelectShowMode(SelectShowMode selectShowMode) {
        mSelectShowMode = selectShowMode;

        refreshView();
    }

    /**
     * 设置内容文字颜色
     *
     * @param checkedColor 选中时的文字颜色
     * @param normalColor  未选中时的文字颜色
     */
    public void setItemTextColor(int checkedColor, int normalColor) {
        this.mCheckedTextColor = checkedColor;
        this.mNormalTextColor = normalColor;

        refreshView();
    }

    /**
     * 设置内容背景
     *
     * @param checkedBackground 选中时的背景
     * @param normalBackground  未选中时的背景
     */
    public void setItemBackground(Drawable checkedBackground, Drawable normalBackground) {
        this.mCheckedBackground = checkedBackground;
        this.mNormalBackground = normalBackground;

        refreshView();
    }

    /**
     * 设置内容背景
     *
     * @param checkedSolidColor  选中时的填充色
     * @param normalSolidColor   未选中时的填充色
     * @param checkedStrokeColor 未选中时的边框色
     * @param normalStrokeColor  未选中时的边框色
     */
    public void setItemBackground(int checkedSolidColor, int normalSolidColor, int checkedStrokeColor, int normalStrokeColor) {
        setItemBackground(checkedSolidColor, normalSolidColor, checkedStrokeColor, normalStrokeColor, mBackgroundStrokeWidth);
    }

    /**
     * 设置内容背景
     *
     * @param checkedSolidColor  选中时的填充色
     * @param normalSolidColor   未选中时的填充色
     * @param checkedStrokeColor 未选中时的边框色
     * @param normalStrokeColor  未选中时的边框色
     * @param strokeWidth        边框线宽，单位：px
     */
    public void setItemBackground(int checkedSolidColor, int normalSolidColor, int checkedStrokeColor, int normalStrokeColor, int strokeWidth) {
        this.mCheckedBackground = null;
        this.mNormalBackground = null;

        this.mCheckedBackgroundSolidColor = checkedSolidColor;
        this.mNormalBackgroundSolidColor = normalSolidColor;
        this.mCheckedBackgroundStrokeColor = checkedStrokeColor;
        this.mNormalBackgroundStrokeColor = normalStrokeColor;
        this.mBackgroundStrokeWidth = strokeWidth;

        refreshView();
    }

    /**
     * 选中所有内容
     */
    public void selectAll() {
        setSelectState(-1, true);
    }

    /**
     * 取消选中所有
     */
    public void cancelSelectAll() {
        setSelectState(-1, false);
    }

    /**
     * 改变指定索引的选中状态
     *
     * @param index 指定索引
     * @param check 指定索引的选中状态
     */
    public void setSelect(int index, boolean check) {
        if (index < 0) {
            throw new IndexOutOfBoundsException();
        }
        setSelectState(index, check);
    }

    /**
     * 改变选中状态，若索引为负数，则改变所有条目状态
     *
     * @param index   要改变状态的条目索引，若为负数，则改变所有条目
     * @param checked true：改为选中；false：改为未选中
     */
    private void setSelectState(int index, boolean checked) {
        if (index < 0) {
            for (int i = 0; i < mAutoNewLineRadioGroup.getChildCount(); i++) {
                View child = mAutoNewLineRadioGroup.getChildAt(i);
                if (mMultiSelect) {
                    if (!(child instanceof CheckBox)) {
                        continue;
                    }
                    ((CheckBox) child).setChecked(checked);
                } else {
                    if (!(child instanceof RadioButton)) {
                        continue;
                    }
                    ((RadioButton) child).setChecked(checked);
                }
            }
        } else {
            if (index >= mAutoNewLineRadioGroup.getChildCount()) {
                throw new IndexOutOfBoundsException();
            }
            ((CompoundButton) mAutoNewLineRadioGroup.getChildAt(index)).setChecked(checked);
        }
    }

    /**
     * 获取当前处于选中状态的条目
     *
     * @return 当前处于选中状态的条目，Key：选中的条目索引数组，根据放入顺序判断；Value：选中的条目文字数组，根据放入顺序判断。
     * 若为单选则只有一条数据
     */
    public SparseArray<String> getSelectState() {
        SparseArray<String> checkedDatas = new SparseArray<>();

        if (mMultiSelect) {
            for (int i = 0; i < mAutoNewLineRadioGroup.getChildCount(); i++) {
                View child = mAutoNewLineRadioGroup.getChildAt(i);
                if (!(child instanceof CheckBox)) {
                    continue;
                }
                if (((CheckBox) child).isChecked()) {
                    checkedDatas.put(i, ((CheckBox) child).getText().toString());
                }
            }
        } else {
            int index = mAutoNewLineRadioGroup.indexOfChild(findViewById(mAutoNewLineRadioGroup.getCheckedRadioButtonId()));
            checkedDatas.put(index, mDataList.get(index));
        }

        return checkedDatas;
    }

    /**
     * 设置当条目选中状态改变时的回调
     *
     * @param onItemCheckedChangeListener 当条目选中状态改变时的回调
     */
    public void setOnItemCheckedChangeListener(OnItemCheckedChangeListener onItemCheckedChangeListener) {
        mOnItemCheckedChangeListener = onItemCheckedChangeListener;
    }

    /**
     * 单选时用的条目选中监听
     */
    private final RadioGroup.OnCheckedChangeListener mOnSingleCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            if (mMultiSelect || mOnItemCheckedChangeListener == null) {
                return;
            }

            int index = group.indexOfChild(findViewById(checkedId));
            mOnItemCheckedChangeListener.onSingleSelectCheckedChange(index, mDataList.get(index));
        }
    };

    /**
     * 多选时的选中状态监听
     */
    private final CompoundButton.OnCheckedChangeListener mOnMultiCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (!mMultiSelect || mOnItemCheckedChangeListener == null) {
                return;
            }

            mOnItemCheckedChangeListener.onMultiSelectCheckedChange(getSelectState());
        }
    };

}
